package org.light4admin.common.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;

/**
 * @author light4admin
 * @date 2018-11-24
 */
@Component
@Aspect
@Slf4j
public class LogAspect {
    private static final String TRACE_ID = "TRACE_ID";

    /**
     * 切入点
     */
    @Pointcut(
            "@annotation(org.springframework.web.bind.annotation.RequestMapping)" +
                    "||@annotation(org.springframework.web.bind.annotation.PostMapping)" +
                    "||@annotation(org.springframework.web.bind.annotation.PutMapping)" +
                    "||@annotation(org.springframework.web.bind.annotation.DeleteMapping)" +
                    "||@annotation(org.springframework.web.bind.annotation.GetMapping)"
    )
    private void pointCut() {
    }


    @Around("pointCut()")
    public Object logAround(ProceedingJoinPoint jp) throws Throwable {
        setTranceId();
        String argsJson = Optional.ofNullable(jp.getArgs())
                .map(arg -> Objects.nonNull(arg) && arg.length >= 1 ? Objects.toString(arg[0], "") : "")
                .orElse("");
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                .getRequest();
        String url = request.getRequestURL().toString();

        log.debug("【接收到请求】url:{} \n,args:{}", url, argsJson);
        Object result = jp.proceed();
        log.debug("【请求响应】 url:{} \n,result:{},traceId:{}", url, result, MDC.get(TRACE_ID));
        return result;
    }

    @After(value = "pointCut()")
    public void after(JoinPoint joinPoint) {
        MDC.remove(TRACE_ID);
    }


    private void setTranceId() {
        String traceId = UUID.randomUUID().toString().replace("-", "");
        if (null == MDC.get(TRACE_ID) || "".equals(MDC.get(TRACE_ID))) {
            MDC.put(TRACE_ID, traceId);
        }
    }
}
